package com.ouroboroswiki.core.content.url.unversioned;

import java.io.File;
import java.io.FileOutputStream;
import java.io.IOException;
import java.io.InputStream;
import java.net.MalformedURLException;
import java.util.ArrayList;
import java.util.Collection;
import java.util.Map;
import java.util.logging.Level;
import java.util.logging.Logger;

import com.ouroboroswiki.core.AbstractContentRepository;
import com.ouroboroswiki.core.Content;
import com.ouroboroswiki.core.ContentException;
import com.ouroboroswiki.core.ContentPath;
import com.ouroboroswiki.core.ContentRepository;
import com.ouroboroswiki.core.ContentUtil;
import com.ouroboroswiki.core.ListableContentRepository;
import com.ouroboroswiki.core.Version;
import com.ouroboroswiki.core.VersionBuilder;
import com.ouroboroswiki.core.WritableContentRepository;
import com.ouroboroswiki.core.content.url.URLContent;


public class UnversionedFileURLContentRepository extends AbstractContentRepository
	implements WritableContentRepository, ListableContentRepository {
	
	private static final Logger log = Logger.getLogger(UnversionedFileURLContentRepository.class.getName());

	private File directory;
	private String pathExtension;
	private String mimeType;
	
	public UnversionedFileURLContentRepository( File directory, String pathExtension ) {
		this.directory = directory;
		this.pathExtension = pathExtension;
	}
	
	public String getMimeType() {
		return mimeType;
	}

	public void setMimeType(String mimeType) {
		this.mimeType = mimeType;
	}

	@Override
	public boolean exists(Object principal,ContentPath path) {
		File file = toFile( path );
		return file.exists();
	}

	@Override
	public Content getContent(Object principal, ContentPath path, Version version, Map<String, Object> properties)
			throws ContentException {
		File file = toFile( path );
		try {
			URLContent content = new URLContent(file.toURI().toURL(), this.getName(), path.getBaseName());
			content.setMimeType(mimeType);
			content.setRepositoryName(this.getName());
			content.setWritable(true);
			return content;
		} catch( MalformedURLException ex ) {
			throw new ContentException( "unable to convert file "+file.getAbsolutePath()+" to URL", ex );
		}
	}
	
	private File toFile( ContentPath path ) {
		return toFile( path.getBaseName() );
	}
	
	private File toFile( String baseName ) {
		File file = new File( directory, baseName + pathExtension );
		return file;
	}
	
	@Override
	public void writeToContent(Object principal, String uniqueId, InputStream ins) 
		throws IOException, ContentException {
		File file = toFile( uniqueId );
		FileOutputStream fos = new FileOutputStream( file );
		try {
			ContentUtil.pipe(ins, fos);
		} finally {
			try {
				fos.close();
			} catch( Exception ex ) {
				log.log( Level.WARNING, "unable to close "+file.getAbsolutePath(), ex );
			}
		}
	}

	@Override
	public Version buildVersion(Object principal, ContentPath path, String[] versionPath, VersionBuilder versionBuilder) {
		return versionBuilder.buildVersion(this.getName(), path.getBaseName(), versionPath, 0);
	}

	@Override
	public Collection<String> listContentIds( Object principal ) throws ContentException {
		// find all the files in the directory that match the postfix
		ArrayList<String> contentIds = new ArrayList<String>();
		listContentIds( directory, contentIds );
		return contentIds;
	}

	protected void listContentIds( File directory, ArrayList<String> contentIds ) {
		File[] files = directory.listFiles();
		for( int i=0; i<files.length; i++ ) {
			File file = files[i];
			if( file.isDirectory() ) {
				listContentIds( file, contentIds );
			} else {
				// TODO : ignore system '/' or '\'
				String absolutePath = file.getAbsolutePath();
				if( absolutePath.endsWith(this.pathExtension ) ) {
					String directoryPath = this.directory.getAbsolutePath();
					String contentId = absolutePath.substring( directoryPath.length() );
					contentId = contentId.substring(0, contentId.length() - this.pathExtension.length() );
					contentIds.add( contentId );
				}
			}
		}
	}
}
